#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import sys
import os
import time
import requests
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from src.db.db_operations import *
from config.config import settings
from scripts.add_update_cases import *

# 尝试导入智谱AI SDK
try:
    from zhipuai import ZhipuAI
    ZHIPU_AVAILABLE = True
except ImportError:
    ZHIPU_AVAILABLE = False
    print("⚠️ 智谱AI SDK未安装，请运行: pip install zhipuai")

def call_ai_model(prompt):
    """调用AI大模型生成内容"""
    try:
        # 根据配置选择AI模型
        ai_model_type = settings.AI_MODEL_TYPE.lower()
        
        if ai_model_type == "zhipu":
            return call_zhipu_model(prompt)
        elif ai_model_type == "openai":
            return call_openai_model(prompt)
        elif ai_model_type == "qwen":
            return call_qwen_model(prompt)
        elif ai_model_type == "doubao":
            return call_doubao_model(prompt)
        else:
            print(f"⚠️ 不支持的AI模型类型: {ai_model_type}")
            return None
            
    except Exception as e:
        print(f"⚠️ AI模型调用异常: {e}")
        return None

def call_zhipu_model(prompt):
    """调用智谱AI模型"""
    try:
        api_key = settings.ZHIPU_API_KEY
        model = settings.ZHIPU_MODEL
        
        if not api_key:
            print("⚠️ 未配置ZHIPU_API_KEY，使用默认规则生成")
            return None
        
        if not ZHIPU_AVAILABLE:
            print("⚠️ 智谱AI SDK未安装，使用默认规则生成")
            return None
        
        # 使用智谱AI SDK
        client = ZhipuAI(api_key=api_key)
        
        response = client.chat.completions.create(
            model=model,
            messages=[
                {
                    "role": "user",
                    "content": prompt
                }
            ],
            max_tokens=1000,
            temperature=0.7
        )
        
        return response.choices[0].message.content.strip()
            
    except Exception as e:
        print(f"⚠️ 智谱AI模型调用异常: {e}")
        return None

def call_openai_model(prompt):
    """调用OpenAI模型"""
    try:
        api_key = settings.OPENAI_API_KEY
        model = settings.OPENAI_MODEL
        
        if not api_key:
            print("⚠️ 未配置OPENAI_API_KEY，使用默认规则生成")
            return None
        
        headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
        
        data = {
            "model": model,
            "messages": [
                {
                    "role": "system",
                    "content": "你是一个API测试用例生成专家，需要根据测试数据生成合适的测试用例名称和描述。"
                },
                {
                    "role": "user",
                    "content": prompt
                }
            ],
            "max_tokens": 500,
            "temperature": 0.7
        }
        
        response = requests.post(
            "https://api.openai.com/v1/chat/completions",
            headers=headers,
            json=data,
            timeout=settings.REQUEST_TIMEOUT
        )
        
        if response.status_code == 200:
            result = response.json()
            return result["choices"][0]["message"]["content"].strip()
        else:
            print(f"⚠️ OpenAI API调用失败: {response.status_code}")
            return None
            
    except Exception as e:
        print(f"⚠️ OpenAI模型调用异常: {e}")
        return None

def call_qwen_model(prompt):
    """调用通义千问模型"""
    try:
        api_key = settings.QWEN_API_KEY
        model = settings.QWEN_MODEL
        
        if not api_key:
            print("⚠️ 未配置QWEN_API_KEY，使用默认规则生成")
            return None
        
        headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
        
        data = {
            "model": model,
            "messages": [
                {
                    "role": "system",
                    "content": "你是一个API测试用例生成专家，需要根据测试数据生成合适的测试用例名称和描述。"
                },
                {
                    "role": "user",
                    "content": prompt
                }
            ],
            "max_tokens": 500,
            "temperature": 0.7
        }
        
        response = requests.post(
            "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation",
            headers=headers,
            json=data,
            timeout=settings.REQUEST_TIMEOUT
        )
        
        if response.status_code == 200:
            result = response.json()
            return result["output"]["text"].strip()
        else:
            print(f"⚠️ 通义千问API调用失败: {response.status_code}")
            return None
            
    except Exception as e:
        print(f"⚠️ 通义千问模型调用异常: {e}")
        return None

def call_doubao_model(prompt):
    """调用豆包AI模型"""
    try:
        api_key = settings.DOUBAO_API_KEY
        model = settings.DOUBAO_MODEL
        base_url = settings.DOUBAO_BASE_URL
        
        if not api_key:
            print("⚠️ 未配置DOUBAO_API_KEY，使用默认规则生成")
            return None
        
        headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
        
        data = {
            "model": model,
            "messages": [
                {
                    "role": "system",
                    "content": "你是一个API测试用例生成专家，需要根据测试数据生成合适的测试用例名称和描述。"
                },
                {
                    "role": "user",
                    "content": prompt
                }
            ],
            "max_tokens": 500,
            "temperature": 0.7
        }
        
        response = requests.post(
            base_url,
            headers=headers,
            json=data,
            timeout=settings.REQUEST_TIMEOUT
        )
        
        if response.status_code == 200:
            result = response.json()
            return result["choices"][0]["message"]["content"].strip()
        else:
            print(f"⚠️ 豆包AI API调用失败: {response.status_code}")
            print(f"响应内容: {response.text}")
            return None
            
    except Exception as e:
        print(f"⚠️ 豆包AI模型调用异常: {e}")
        return None

def generate_case_with_ai(data, field_generation_types, scenario, required_fields):
    """使用AI大模型生成测试用例信息"""
    
    # 构建AI提示词
    prompt = f"""
请根据以下测试数据信息，生成一个合适的测试用例名称和描述：

测试数据信息：
- 场景(scenario): {scenario}
- 字段具体情况列表（none,exception,normal）: {json.dumps(field_generation_types, ensure_ascii=False, indent=2)}
- 必填字段详情: {json.dumps(required_fields, ensure_ascii=False, indent=2)}
- 实际数据: {json.dumps(data, ensure_ascii=False, indent=2)}

分析规则：
1. 必填字段缺失判断：只有当字段在必填字段列表中，且字段具体情况为"none"时，才算必填字段缺失
2. 异常字段判断：字段具体情况为"invalid"的字段（有值但异常）
3. 正常数据：所有必填字段都有值（字段具体情况不为"none"），且没有异常字段

字段具体情况含义：
- "none": 字段缺失（没有值）
- "normal": 字段有正常值
- "invalid": 字段有值但异常（不是缺失！）

判断步骤：
1. 先检查必填字段列表中的字段
2. 对于每个必填字段，查看其字段具体情况：
   - 如果是"none"，说明该必填字段缺失
   - 如果是"normal"或"invalid"，说明该必填字段有值（不是缺失）
3. 再检查所有字段具体情况为"invalid"的字段，你可以根据data中的invalid字段的具体数值猜想具体的异常类型，如异常字符、过长等，写到描述里

重要提醒：
- 只有字段具体情况为"none"的必填字段才算缺失
- 字段具体情况为"normal"或"invalid"的必填字段不算缺失，它们有值
- "invalid"表示字段有值但异常，不是缺失！
- 非必填字段即使为"none"也不算缺失

要求：
- 测试用例名称要简洁明了，体现测试重点，主要为概括性文字，不需要特别详细，名称里不用出现具体的异常字段名称！！。不超过20个字符
- 测试用例描述不超过100个字符，可以具体说明异常字段和异常类型
- 测试用例名称要包含测试用例类型，如：创建记录-必填字段缺失，创建记录-正常数据，创建记录-数据异常
- 如果同时存在缺失必填值和字段异常的情况，测试用例名称优先为必填字段缺失，描述里面可提到字段异常的情况。
- 使用中文
- 不要包含任何其他格式，只需要两行文本

返回格式只要两行：
第一行：生成的测试用例名称，如“创建记录-正常数据”，“创建记录-必填字段缺失”，“创建记录-数据异常”
第二行：生成的测试用例描述

请根据实际数据生成对应的测试用例名称和描述：

"""

    # 调用AI模型
    print(f"🔄 正在调用AI生成测试用例...")
    ai_response = call_ai_model(prompt)
    
    if ai_response:
        print(f"✅ AI返回原始内容:")
        print(f"---AI开始---")
        print(ai_response)
        print(f"---AI结束---")
        
        try:
            # 清理AI返回的内容
            cleaned_response = ai_response.strip()
            
            # 移除可能的markdown格式
            cleaned_response = cleaned_response.replace('**', '').replace('*', '')
            cleaned_response = cleaned_response.replace('测试用例名称：', '').replace('测试用例描述：', '')
            cleaned_response = cleaned_response.replace('测试用例名称:', '').replace('测试用例描述:', '')
            
          
            # 按行分割
            lines = [line.strip() for line in cleaned_response.split('\n') if line.strip()]
            
            
            # 查找包含"测试"或"用例"的行作为case_name
            case_name = None
            description = None
            
            for i, line in enumerate(lines):
                if '测试' in line or '用例' in line or '创建' in line:
                    case_name = line
                    # 下一行作为description
                    if i + 1 < len(lines):
                        description = lines[i + 1]
                    break
            
            # 如果没有找到合适的case_name，使用前两行
            if not case_name and len(lines) >= 2:
                case_name = lines[0]
                description = lines[1]
            elif not case_name and len(lines) >= 1:
                case_name = lines[0]
                description = "测试用例描述"
            
            print(f"提取结果:")
            print(f"  case_name: {case_name}")
            print(f"  description: {description}")
            
            if case_name:
                return {
                    "case_name": case_name,
                    "description": description or "测试用例描述",
                    "case_type": "create",
                    "expected_result": "创建成功，返回记录ID" if scenario == "normal" else "创建失败，返回相应错误信息"
                }
            else:
                print(f"⚠️ 无法从AI返回内容中提取case_name: {ai_response}")
                
        except Exception as e:
            print(f"⚠️ AI返回内容解析失败: {e}")
            print(f"AI返回内容: {ai_response}")
    else:
        print(f"❌ AI调用失败，返回None")
    
    # 如果AI调用失败，使用默认规则
    print(f"🔄 回退到默认规则生成...")
    return generate_case_with_rules(data, field_generation_types, scenario, required_fields)

def generate_case_with_rules(data, field_generation_types, scenario, required_fields):
    """使用规则生成测试用例信息（备用方案）"""
    
    # 1. 检查必填字段缺失（优先级最高）
    missing_required_fields = []
    for field_name, generate_type in field_generation_types.items():
        if field_name in required_fields and required_fields[field_name] and generate_type == "none":
            missing_required_fields.append(field_name)
    
    if missing_required_fields:
        return {
            "case_name": f"创建记录-必填字段缺失",
            "description": f"必填字段 {', '.join(missing_required_fields)} 为空，导致创建失败",
            "case_type": "create",
            "expected_result": "创建失败，返回必填字段缺失错误"
        }
    
    # 2. 检查异常字段
    invalid_fields = []
    for field_name, generate_type in field_generation_types.items():
        if generate_type == "invalid":
            invalid_fields.append(field_name)
    
    if invalid_fields:
        # 根据字段类型分类异常
        field_type_abnormalities = {}
        for field_name in invalid_fields:
            # 从字段名推断字段类型
            if "text" in field_name:
                field_type_abnormalities["文本"] = field_type_abnormalities.get("文本", []) + [field_name]
            elif "number" in field_name or "bigint" in field_name or "decimal" in field_name:
                field_type_abnormalities["数字"] = field_type_abnormalities.get("数字", []) + [field_name]
            elif "date" in field_name or "datetime" in field_name:
                field_type_abnormalities["日期时间"] = field_type_abnormalities.get("日期时间", []) + [field_name]
            elif "email" in field_name:
                field_type_abnormalities["邮箱"] = field_type_abnormalities.get("邮箱", []) + [field_name]
            elif "phone" in field_name:
                field_type_abnormalities["电话"] = field_type_abnormalities.get("电话", []) + [field_name]
            elif "option" in field_name:
                field_type_abnormalities["选项"] = field_type_abnormalities.get("选项", []) + [field_name]
            elif "boolean" in field_name:
                field_type_abnormalities["布尔"] = field_type_abnormalities.get("布尔", []) + [field_name]
            elif "region" in field_name:
                field_type_abnormalities["地区"] = field_type_abnormalities.get("地区", []) + [field_name]
            elif "attachment" in field_name:
                field_type_abnormalities["附件"] = field_type_abnormalities.get("附件", []) + [field_name]
            elif "avatar" in field_name:
                field_type_abnormalities["头像"] = field_type_abnormalities.get("头像", []) + [field_name]
            elif "multilingual" in field_name:
                field_type_abnormalities["多语言"] = field_type_abnormalities.get("多语言", []) + [field_name]
            else:
                field_type_abnormalities["其他"] = field_type_abnormalities.get("其他", []) + [field_name]
        
        # 生成异常描述
        abnormality_descriptions = []
        for field_type, fields in field_type_abnormalities.items():
            if len(fields) == 1:
                abnormality_descriptions.append(f"{field_type}字段{fields[0]}异常")
            else:
                abnormality_descriptions.append(f"{field_type}字段{', '.join(fields)}异常")
        
        return {
            "case_name": f"创建记录-{'和'.join(abnormality_descriptions)}",
            "description": f"包含异常字段: {', '.join(invalid_fields)}，可能导致数据验证失败",
            "case_type": "create",
            "expected_result": "创建失败，返回数据验证错误"
        }
    
    # 3. 正常情况
    if scenario == "normal":
        return {
            "case_name": "创建记录-正常数据",
            "description": "使用所有字段的正常数据创建记录",
            "case_type": "create",
            "expected_result": "创建成功，返回记录ID"
        }
    
    # 4. 其他异常情况
    return {
        "case_name": "创建记录-数据异常",
        "description": "数据包含异常情况，可能导致创建失败",
        "case_type": "create",
        "expected_result": "创建失败，返回相应错误信息"
    }

def get_field_requirements(object_id: str):
    """获取字段的必填性信息"""
    try:
        dbrunner = DbRunner(settings.DB_HOST, settings.DB_USER, settings.DB_PASSWORD, settings.DB_NAME)
        select_result = dbrunner.select_data('field_schema', columns='*', where=f"object_api_name = {object_id}")
        dbrunner.close()
        
        # 需要过滤的系统字段
        system_fields_to_filter = [
            '_id',
            '_createdBy',
            '_createdAt',
            '_updatedBy',
            '_updatedAt'
        ]
        
        required_fields = {}
        for field in select_result:
            field_name = field["field_api_name"]
            
            # 过滤掉系统字段
            if field_name in system_fields_to_filter:
                continue
                
            is_required = field.get("is_required", 0)
            # 只保留真正的必填字段（is_required = 1）
            if is_required == 1:
                required_fields[field_name] = True
        
        return required_fields
    except Exception as e:
        print(f"获取字段必填性信息失败: {e}")
        return {}

def generate_test_cases(input_file: str = "data/tmp.json", output_file: str = "data/test_cases.json", use_ai: bool = True):
    """生成测试用例"""
    
    print(f"开始分析 {input_file} 文件...")
    
    # 读取输入文件
    try:
        with open(input_file, 'r', encoding='utf-8') as f:
            data = json.load(f)
    except FileNotFoundError:
        print(f"❌ 文件 {input_file} 不存在")
        return
    except json.JSONDecodeError as e:
        print(f"❌ JSON文件格式错误: {e}")
        return
    
    # 获取字段必填性信息
    object_id = data.get("object_id", '"object_cbb246f2bd1"')
    required_fields = get_field_requirements(object_id)
    
    print(f"✅ 成功获取字段必填性信息，共 {len(required_fields)} 个字段")
    
    # 生成测试用例
    test_cases = []
    
    # 在test_cases数组最前面添加固定的正常测试用例
    fixed_normal_case = {
        "case_name": "创建记录-正常数据",
        "case_type": "create",
        "scenario": "normal",
        "description": "使用所有字段的正常数据创建记录",
        "test_data": {
          "text_7ea7d6a3339": "一直手机还是.这是完成现在全国.\n但是帖子软件价格.\n地址之后中文时间觉得规定.美国个人类别相关可能知道.说明部分关系投资客户等级.\n之间东西决定女人男人.重要得到空间.很多可能那么威望生活.",
          "bigint_7d6a33398bf": "-610242057301765",
          "number_a33398bfae5": 500532581698672.56,
          "date_398bfae52d8": "1981-09-18",
          "datetime_bfae52d8694": 1831240879423,
          "option_e52d86948bb": "option_52d86948bb9",
          "boolean_e206a267520": False,
          "multilingual_24673c280f2": {
            "zh_cn": "免费以上浏览运行开始还是.是一这么大学设备社会准备什么.作者这个文章必须业务只有内容.\n全部无法当前完全中国系列行业投资.两个资料的是在线我们.客户最大显示我的简介.\n价格音乐国家拥有历史帮助组织怎么.不断以后一种环境.活动标准系统可是.\n类别北京方法这里文件事情只有.不断分析程序数据看到.\n质量那么推荐使用信息感觉.地址市场经营最后一起完全市场这些.个人有限那些一样首页她的部分.\n网络学生只有研究.结果空间提供.\n能够文章游戏投资还是上海.一些历史不同决定这里他们准备.当前以下社区.\n单位免费看到问题可能空间.以下她的经济规定关系.\n支持选择当前那个一般这么已经.方法增加无法已经显示品牌进行进行.精华计划一样那个工作.\n地区起来成为目前合作日期.电子结果其他成为城市.\n还有准备全部.是一显示有限点击.\n而且在线威望男人作品.时间人民其他直接密码公司电话.\n支持图片不是状态表示是否帖子.一起谢谢作者只有生产.\n日本作为目前一直这里回复.\n如果制作有些进入.\n感觉大学论坛名称应用客户工作出现.登录不会你们今年客户.以下同时生活加入.\n下载比较人员应用能够决定.你的责任文章事情完全.",
            "en_us": "Go meeting quickly such former. Boy wife condition.\nBoard its rock. Job worker break tonight couple and.\nMind southern rather. Hair attorney professional form finish. Rest feel finally impact.\nNever court professor here security. Past feeling nature a. Decision size parent focus kid.\nList top somebody college be middle plan. Behavior weight dog financial southern challenge.\nWorker particularly shoulder lay though."
          },
          "phone_73c280f2783": {
            "dialing_code": "+86",
            "country_code": "CN",
            "number": "14557986872"
          },
          "email_f2783b49d9a": "qsu@example.org",
          "decimal_a446e77c109": "934892733277720.528"
        },
        "expected_result": "创建成功，返回记录ID"
    }
    
    # 将固定的正常测试用例添加到数组最前面
    test_cases.append(fixed_normal_case)
    
    results = data.get("results", [])
    
    print(f"开始处理 {len(results)} 条数据...")
    print(f"使用AI生成: {'是' if use_ai else '否'}")
    print(f"AI模型类型: {settings.AI_MODEL_TYPE}")
    
    for i, result in enumerate(results):
        print(f"正在处理第 {i+1}/{len(results)} 条数据...")
        
        # 根据配置选择生成方式
        if use_ai:
            case_info = generate_case_with_ai(
                result["data"], 
                result["field_generation_types"], 
                result["scenario"], 
                required_fields
            )
        else:
            case_info = generate_case_with_rules(
                result["data"], 
                result["field_generation_types"], 
                result["scenario"], 
                required_fields
            )
        
        # 构建测试用例
        test_case = {
            "case_name": case_info["case_name"],
            "case_type": case_info["case_type"],
            "scenario": result["scenario"],
            "description": case_info["description"],
            "test_data": result["data"],
            "expected_result": case_info["expected_result"]
        }
        
        test_cases.append(test_case)
        
        print(f"  生成测试用例: {case_info['case_name']}")
    
    # 构建输出数据 - 按照test_cases.json的格式
    # 提取object_id，去掉引号
    clean_object_id = object_id.strip('"')
    
    output_data = {
        clean_object_id: {
            "generated_at": str(int(time.time())),
            "test_cases": test_cases
        }
    }
    
    # 保存到输出文件
    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(output_data, f, 
                 ensure_ascii=False,  # 确保非ASCII字符正常显示
                 indent=2,            # 缩进格式化
                 sort_keys=True)
    
    print(f"\n✅ 成功生成 {len(test_cases)} 个测试用例并保存到 {output_file}")
    
    # 统计测试用例类型
    case_type_stats = {}
    for test_case in test_cases:
        case_name = test_case["case_name"]
        case_type_stats[case_name] = case_type_stats.get(case_name, 0) + 1
    
    print(f"\n📊 测试用例类型统计:")
    for case_name, count in case_type_stats.items():
        percentage = (count / len(test_cases)) * 100
        print(f"  {case_name}: {count} 个 ({percentage:.1f}%)")

if __name__ == "__main__":
    # 生成测试用例 - 默认使用AI生成
    generate_test_cases("data/data_tmp.json", "data/test_cases.json", use_ai=True) 
   
    add_update_cases_to_test_cases()
    add_delete_cases_to_test_cases()